package com.flyqiu.flow.api.service;

import com.alibaba.fastjson2.JSONObject;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.flyqiu.common.tools.StringTools;
import com.flyqiu.common.user.FlyQiuUser;
import com.flyqiu.flow.model.business.BaseFlyBusiness;
import com.flyqiu.flow.api.context.ProcInstContext;
import com.flyqiu.flow.common.std.IProIcActivityMove;
import com.flyqiu.flow.model.entity.Comment;
import com.flyqiu.flow.model.entity.ru.ProcRuActivity;
import com.flyqiu.flow.model.entity.ru.ProcRuIdentityLink;
import com.flyqiu.flow.model.entity.ru.ProcRuUserTask;

import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * 任务服务
 */
public interface FlowTaskService {
    /**
     * 列表查询任务实例
     *
     * @param wrapper 查询条件
     * @return 正在执行的用户任务 {@link ProcRuUserTask}
     */
    List<ProcRuUserTask> listTask(Wrapper<ProcRuUserTask> wrapper);

    /**
     * 分页查询任务实例
     *
     * @param page    分页信息
     * @param wrapper 查询条件
     * @return 正在执行的用户任务 {@link ProcRuUserTask}
     */
    Page<ProcRuUserTask> pageTask(Page<ProcRuUserTask> page, Wrapper<ProcRuUserTask> wrapper);


    default List<ProcRuUserTask> listTaskByProcInstId(String procInstId) {
        LambdaQueryWrapper<ProcRuUserTask> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(ProcRuUserTask::getProcInstId, procInstId);
        queryWrapper.orderByDesc(ProcRuUserTask::getCreateTime);
        return listTask(queryWrapper);
    }

    /**
     * 获取流程任务
     *
     * @param taskInstId
     * @return
     */
    default ProcRuUserTask getTaskById(String taskInstId) {
        LambdaQueryWrapper<ProcRuUserTask> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(ProcRuUserTask::getId, taskInstId);
        return selectOneTaskInst(queryWrapper);
    }

    ProcRuUserTask selectOneTaskInst(Wrapper<ProcRuUserTask> wrapper);


    /**
     * 查询任务数量
     *
     * @param wrapper
     * @return
     */
    long countTask(Wrapper<ProcRuUserTask> wrapper);

    default void addVariable(String taskInstId, String varName, Object val) {
        if (StringTools.isAllBlank(taskInstId)) {
            throw new RuntimeException("taskInstId  cannot be null or empty");
        }
        if (StringTools.isAllBlank(varName)) {
            throw new RuntimeException("varName  cannot be null or empty");
        }
        JSONObject taskVariable = new JSONObject();
        taskVariable.put(varName, val);
        addVariable(taskInstId, taskVariable);
    }

    /**
     * 添加任务变量
     *
     * @param taskInstId   任务实例id
     * @param taskVariable 任务变量
     */
    void addVariable(String taskInstId, JSONObject taskVariable);

    /**
     * 设置任务业务信息
     *
     * @param taskInstId 任务实例id
     * @param business   业务信息
     */
    void setBusiness(String taskInstId, BaseFlyBusiness business);

    /**
     * 删除业务信息
     *
     * @param taskInstId 任务实例信息
     */
    void deleteBusiness(String taskInstId);

    /**
     * 添加备注
     *
     * @param taskInstId
     * @param type
     * @param msg
     */
    default void addComment(String taskInstId, String type, String msg) {
        addComment(taskInstId, type, msg, null);
    }


    /**
     * 添加备注
     *
     * @param taskInstId 任务实例id
     * @param type       类型
     * @param msg        消息内容
     * @param extParams  消息内容
     */
    void addComment(String taskInstId, String type, String msg, JSONObject extParams);

    default List<Comment> listCommentByProcInstId(String procInstId) {
        LambdaQueryWrapper<Comment> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Comment::getProcInstId, procInstId);
        return listComment(queryWrapper);
    }

    default List<Comment> listCommentByTaskInstId(String taskInstId) {
        LambdaQueryWrapper<Comment> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Comment::getActInstId, taskInstId);
        return listComment(queryWrapper);
    }

    /**
     * 任务添加候选人
     *
     * @param taskInstId    任务实例id
     * @param candidateUser 候选人信息
     */
    default void addCandidateUser(String taskInstId, FlyQiuUser candidateUser) {
        if (StringUtils.checkValNull(candidateUser)) return;
        HashSet<FlyQiuUser> hashSet = Stream.of(candidateUser).collect(Collectors.toCollection(HashSet::new));
        addCandidateUser(taskInstId, hashSet);
    }

    /**
     * 任务添加候选人
     *
     * @param taskInstId     任务实例id
     * @param candidateUsers 候选人信息
     */
    void addCandidateUser(String taskInstId, Set<? extends FlyQiuUser> candidateUsers);


    /**
     * 删除候选人
     *
     * @param taskInstId    任务实例id
     * @param userUniqueKey 用户唯一key userUniqueKey默认生成逻辑 {@link FlyQiuUser#getUniqueKey()}
     */
    default void delCandidateUser(String taskInstId, String userUniqueKey) {
        if (StringUtils.checkValNull(userUniqueKey)) return;
        HashSet<String> hashSet = Stream.of(userUniqueKey).collect(Collectors.toCollection(HashSet::new));
        delCandidateUser(taskInstId, hashSet);
    }

    /**
     * 删除候选人
     *
     * @param taskInstId     任务实例id
     * @param userUniqueKeys 用户唯一key集合 userUniqueKey默认生成逻辑 {@link FlyQiuUser#getUniqueKey()}
     */
    void delCandidateUser(String taskInstId, Set<String> userUniqueKeys);


    /**
     * 获取候选人
     *
     * @param taskInstId 任务实例id
     * @return 任务关系人员信息集合 {@link ProcRuIdentityLink}
     */
    List<ProcRuIdentityLink> getIdentityLink(String taskInstId);


    /**
     * 删除审批备注
     *
     * @param commentId 意见id
     */
    void deleteComment(String commentId);

    /**
     * 修改备注
     *
     * @param commentId 意见id
     * @param type      意见类型
     * @param message   消息内容
     */
    void updateComment(String commentId, String type, String message);

    /**
     * 查询审批备注
     *
     * @param wrapper 查询条件
     * @return 审批备注 {@link Comment}
     */
    List<Comment> listComment(Wrapper<Comment> wrapper);

    /**
     * 获取任务上下文
     *
     * @param taskInstId 任务实例id
     * @return 任务上下文 {@link ProcInstContext}
     */
    ProcInstContext getRunTaskContext(String taskInstId);


    void complete(String taskInstId);


    /**
     * 设置任务持有人
     *
     * @param taskInstId 任务实例id
     * @param ownerUser  任务持有人
     */
    void setOwner(String taskInstId, FlyQiuUser ownerUser);

    /**
     * 设置任务审批人
     *
     * @param taskInstId   任务实例id
     * @param assigneeUser 任务办理人
     */
    void setAssignee(String taskInstId, FlyQiuUser assigneeUser);

    /**
     * 委派任务
     *
     * @param taskInstId   任务实例id
     * @param delegateUser 任务委派人
     */
    void delegate(String taskInstId, FlyQiuUser delegateUser);

    /**
     * 解决委派任务
     *
     * @param taskInstId 任务实例id
     */
    void resolve(String taskInstId);

    /**
     * 任务活动移动到目标位置
     *
     * @param taskInstId   当前活动id
     * @param targetDefKey 目标定义key
     * @return 运行活动 {@link ProcRuActivity}
     */
    List<ProcRuUserTask>  taskMoveTo(String taskInstId, String targetDefKey);

    /**
     * 任务活动移动到目标位置
     *
     * @param taskInstId   活动id
     * @param targetDefKey 目标定义key
     * @param move         移动策略执行器
     * @return 运行活动 {@link ProcRuActivity}
     */

    List<ProcRuUserTask>  taskMoveTo(String taskInstId, String targetDefKey, IProIcActivityMove move);

}
